﻿Imports System.Data.OleDb

Public Class Dal

#Region "Algemeen"

    Public Shared Sub Toevoegen(ByVal row As DataRow)
        Dim artRow As ArtikelsDataSet.ArtikelsRow = TryCast(row, ArtikelsDataSet.ArtikelsRow)
        If (artRow IsNot Nothing) Then
            ArtikelToevoegen(artRow)
            Return
        End If
        Dim catRow As ArtikelsDataSet.CategorieenRow = TryCast(row, ArtikelsDataSet.CategorieenRow)
        If (catRow IsNot Nothing) Then
            CategorieToevoegen(catRow)
            Return
        End If
        Dim winkRow As ArtikelsDataSet.WinkeliersRow = TryCast(row, ArtikelsDataSet.WinkeliersRow)
        If (winkRow IsNot Nothing) Then
            WinkelierToevoegen(winkRow)
            Return
        End If
        Dim levRow As ArtikelsDataSet.LeveranciersRow = TryCast(row, ArtikelsDataSet.LeveranciersRow)
        If (levRow IsNot Nothing) Then
            LeverancierToevoegen(levRow)
            Return
        End If
        Dim klantRow As ArtikelsDataSet.KlantenRow = TryCast(row, ArtikelsDataSet.KlantenRow)
        If (klantRow IsNot Nothing) Then
            KlantToevoegen(klantRow)
            Return
        End If
        'Dim bewegingenRow As ArtikelsDataSet.VoorraadbewegingenRow = TryCast(row, ArtikelsDataSet.VoorraadbewegingenRow)
        'If (bewegingenRow IsNot Nothing) Then
        '    VoorraadBewegingToevoegen(bewegingenRow, True, False)
        '    Return
        'End If
        Throw New InvalidOperationException(String.Format("Het type rij {0} kan nog niet toegevoegd worden met Dal.Toevoegen", row.GetType().ToString()))
    End Sub

    Public Shared Function Bijwerken(ByVal table As DataTable) As Integer
        Dim artTable As ArtikelsDataSet.ArtikelsDataTable = TryCast(table, ArtikelsDataSet.ArtikelsDataTable)
        If (artTable IsNot Nothing) Then
            Dim adapter As New ArtikelsDataSetTableAdapters.ArtikelsTableAdapter()
            Return adapter.Update(artTable)
        End If
        Dim catTable As ArtikelsDataSet.CategorieenDataTable = TryCast(table, ArtikelsDataSet.CategorieenDataTable)
        If (catTable IsNot Nothing) Then
            Dim adapter As New ArtikelsDataSetTableAdapters.CategorieenTableAdapter()
            Return adapter.Update(catTable)
        End If
        Dim winkTable As ArtikelsDataSet.WinkeliersDataTable = TryCast(table, ArtikelsDataSet.WinkeliersDataTable)
        If (winkTable IsNot Nothing) Then
            Dim adapter As New ArtikelsDataSetTableAdapters.WinkeliersTableAdapter()
            Return adapter.Update(winkTable)
        End If
        Dim levTable As ArtikelsDataSet.LeveranciersDataTable = TryCast(table, ArtikelsDataSet.LeveranciersDataTable)
        If (levTable IsNot Nothing) Then
            Dim adapter As New ArtikelsDataSetTableAdapters.LeveranciersTableAdapter()
            Return adapter.Update(levTable)
        End If
        Dim verkopenTable As ArtikelsDataSet.VerkopenDataTable = TryCast(table, ArtikelsDataSet.VerkopenDataTable)
        If (verkopenTable IsNot Nothing) Then
            Dim adapter As New ArtikelsDataSetTableAdapters.VerkopenTableAdapter()
            Return adapter.Update(verkopenTable)
        End If
        Dim klantTable As ArtikelsDataSet.KlantenDataTable = TryCast(table, ArtikelsDataSet.KlantenDataTable)
        If (klantTable IsNot Nothing) Then
            Dim adapter As New ArtikelsDataSetTableAdapters.KlantenTableAdapter()
            Return adapter.Update(klantTable)
        End If
        Dim verkoopsdetailsTable As ArtikelsDataSet.VerkoopsDetailsDataTable = TryCast(table, ArtikelsDataSet.VerkoopsDetailsDataTable)
        If (verkoopsdetailsTable IsNot Nothing) Then
            'Dim adapter As New ArtikelsDataSetTableAdapters.VerkoopsDetailsTableAdapter()
            'Return adapter.Update(verkoopsdetailsTable) ' werkt niet omdat de adapter een join gebruikt
            Dim conn As New OleDbConnection(My.Settings.fairshopConnectionString)
            Try
                conn.Open()
                Dim sql As String = "SELECT Id, IdVerkoop, VolgnummerKlant, IdArtikel, Prijs, StatiegeldEuro, Aantal, ExtraOmschrijving FROM VerkoopsDetails"
                Dim cm As New OleDbCommand(sql, conn)
                Dim da As New OleDbDataAdapter(cm)
                Dim cb As New OleDbCommandBuilder(da)
                Return da.Update(verkoopsdetailsTable)
            Finally
                conn.Close()
            End Try
        End If
        Dim leveringdetailsTable As ArtikelsDataSet.LeveringDetailsDataTable = TryCast(table, ArtikelsDataSet.LeveringDetailsDataTable)
        If (leveringdetailsTable IsNot Nothing) Then
            Dim adapter As New ArtikelsDataSetTableAdapters.LeveringDetailsTableAdapter()
            Return adapter.Update(leveringdetailsTable)
        End If
        Dim samengesteldeArtikelsTable As SamengesteldeArtikelsDataSet.SamengesteldeArtikelsDataTable = TryCast(table, SamengesteldeArtikelsDataSet.SamengesteldeArtikelsDataTable)
        If (samengesteldeArtikelsTable IsNot Nothing) Then
            Dim adapter As New SamengesteldeArtikelsDataSetTableAdapters.SamengesteldeArtikelsTableAdapter()
            Return adapter.Update(samengesteldeArtikelsTable)
        End If
        'Dim bewegingenTable As ArtikelsDataSet.VoorraadbewegingenDataTable = TryCast(table, ArtikelsDataSet.VoorraadbewegingenDataTable)
        'If (bewegingenTable IsNot Nothing) Then
        '    Dim adapter As New ArtikelsDataSetTableAdapters.VoorraadbewegingenTableAdapter()
        '    Return adapter.Update(bewegingenTable)
        'End If
        Throw New InvalidOperationException(String.Format("Dit type tabel {0} kan nog niet bijgewerkt worden met Dal.Bijwerken", table.GetType().ToString()))
    End Function

    ''' <summary>
    ''' Vult een ArtikelsDataset met de meest gebruikte data.
    ''' </summary>
    ''' <returns></returns>
    Public Shared Function PrepareArtikelsDataset() As ArtikelsDataSet
        Using conn As New OleDbConnection(My.Settings.fairshopConnectionString)
            Try
                conn.Open()
                Return PrepareArtikelsDataset(conn)
            Finally
                conn.Close()
            End Try
        End Using
    End Function

    ''' <summary>
    ''' Vult een ArtikelsDataset met de meest gebruikte data.
    ''' </summary>
    ''' <param name="conn">Connectie (moet al open zijn)</param>
    ''' <returns></returns>
    Public Shared Function PrepareArtikelsDataset(ByVal conn As OleDbConnection) As ArtikelsDataSet
        Dim prf As New PerformantieHelper("Dal: PrepareArtikelsDataset")
        Dim ds As New ArtikelsDataSet
        ds.EnforceConstraints = False
        Dim leveranciersAdapter As New ArtikelsDataSetTableAdapters.LeveranciersTableAdapter
        leveranciersAdapter.Connection = conn
        leveranciersAdapter.Fill(ds.Leveranciers)
        Dim categorieenAdapter As New ArtikelsDataSetTableAdapters.CategorieenTableAdapter
        categorieenAdapter.Connection = conn
        categorieenAdapter.Fill(ds.Categorieen)
        Dim klantenAdapter As New ArtikelsDataSetTableAdapters.KlantenTableAdapter
        klantenAdapter.Connection = conn
        klantenAdapter.Fill(ds.Klanten)
        Dim winkeliersAdapter As New ArtikelsDataSetTableAdapters.WinkeliersTableAdapter
        winkeliersAdapter.Connection = conn
        winkeliersAdapter.Fill(ds.Winkeliers)
        Dim verkoopsoortenAdapter As New ArtikelsDataSetTableAdapters.VerkoopsoortenTableAdapter
        verkoopsoortenAdapter.Connection = conn
        verkoopsoortenAdapter.Fill(ds.Verkoopsoorten)
        Dim artikelsAdapter As New ArtikelsDataSetTableAdapters.ArtikelsTableAdapter
        artikelsAdapter.Connection = conn
        artikelsAdapter.Fill(ds.Artikels)
        Dim leveringenAdapter As New ArtikelsDataSetTableAdapters.LeveringenTableAdapter
        leveringenAdapter.Connection = conn
        leveringenAdapter.Fill(ds.Leveringen)
        Dim leveringDetailsAdapter As New ArtikelsDataSetTableAdapters.LeveringDetailsTableAdapter
        leveringDetailsAdapter.Connection = conn
        leveringDetailsAdapter.Fill(ds.LeveringDetails)
        Dim verkopenAdapter As New ArtikelsDataSetTableAdapters.VerkopenTableAdapter
        verkopenAdapter.Connection = conn
        verkopenAdapter.Fill(ds.Verkopen)
        Dim verkoopDetailsAdapter As New ArtikelsDataSetTableAdapters.VerkoopsDetailsTableAdapter
        verkoopDetailsAdapter.Connection = conn
        verkoopDetailsAdapter.Fill(ds.VerkoopsDetails)
        For Each row As ArtikelsDataSet.VerkoopsDetailsRow In ds.VerkoopsDetails
            ' omschrijving nog invullen vanuit Artikels-tabel
            row.Omschrijving = row.ArtikelsRow.Omschrijving
            ' berekende kolommen nog invullen
            row.Totaal = row.Prijs * row.Aantal
            row.Status = StatusImage.Afgerekend
        Next
        Dim voorraadbewegingenAdapter As New ArtikelsDataSetTableAdapters.VoorraadbewegingenTableAdapter
        voorraadbewegingenAdapter.Connection = conn
        voorraadbewegingenAdapter.FillWithArtikel(ds.Voorraadbewegingen)
        Dim meldingenAdapter As New ArtikelsDataSetTableAdapters.MeldingenTableAdapter
        meldingenAdapter.Connection = conn
        meldingenAdapter.Fill(ds.Meldingen)
        ds.EnforceConstraints = True
        ds.AcceptChanges()
        prf.LogMeting()
        Return ds
    End Function

    Public Shared Sub VerversArtikelsFromDatabase(ByVal data As ArtikelsDataSet)
        Using conn As New OleDbConnection(My.Settings.fairshopConnectionString)
            Try
                conn.Open()
                Dim ds As New ArtikelsDataSet
                ds.EnforceConstraints = False
                Dim leveranciersAdapter As New ArtikelsDataSetTableAdapters.LeveranciersTableAdapter
                leveranciersAdapter.Connection = conn
                leveranciersAdapter.Fill(ds.Leveranciers)
                data.Leveranciers.Merge(ds.Leveranciers, False)

                Dim categorieenAdapter As New ArtikelsDataSetTableAdapters.CategorieenTableAdapter
                categorieenAdapter.Connection = conn
                categorieenAdapter.Fill(ds.Categorieen)
                data.Categorieen.Merge(ds.Categorieen, False)

                Dim artikelsAdapter As New ArtikelsDataSetTableAdapters.ArtikelsTableAdapter
                artikelsAdapter.Connection = conn
                artikelsAdapter.Fill(ds.Artikels)
                data.Artikels.Merge(ds.Artikels, False)
            Finally
                conn.Close()
            End Try
        End Using
    End Sub

#End Region

#Region "Artikels"

    Public Shared Sub ArtikelToevoegen(ByVal row As ArtikelsDataSet.ArtikelsRow)
        ' nodig omdat de nieuwe ID anders niet opgehaald wordt.
        ' als je dan daarna nog eens bewaart, krijg je een fout
        Dim conn As New OleDbConnection(My.Settings.fairshopConnectionString)
        Try
            conn.Open()
            Dim strSQL As String = "INSERT INTO `Artikels` (`Omschrijving`, `Artikelcode`, `Barcode`, `Verkoopbaar`, " & _
                "`Voorraad`, `AantalPerVerpakking`, `Prijs`, `StatiegeldEuro`, `Inkoopprijs`, " & _
                "`BTW`, `IdLeverancier`, `IsLeeggoed`, `IsCheque`, `IdCategorie`, `VerwachteVoorraad`, KortingLeverancier, DatumToegevoegd) " & _
                "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW())"
            Dim cm1 As New OleDbCommand(strSQL, conn)
            ' let op: volgorde moet dezelfde zijn als hierboven
            DalHelper.VoegParameterToe(cm1, row.Omschrijving)
            DalHelper.VoegParameterToe(cm1, row.Artikelcode)
            DalHelper.VoegParameterToe(cm1, row.Barcode)
            DalHelper.VoegParameterToe(cm1, row.Verkoopbaar)
            DalHelper.VoegParameterToe(cm1, row.Voorraad)
            DalHelper.VoegParameterToe(cm1, row.AantalPerVerpakking)
            DalHelper.VoegParameterToe(cm1, row.Prijs)
            DalHelper.VoegParameterToe(cm1, row.StatiegeldEuro)
            DalHelper.VoegParameterToe(cm1, row.Inkoopprijs)
            DalHelper.VoegParameterToe(cm1, Convert.ToDecimal(row.BTW))
            DalHelper.VoegParameterToe(cm1, row.IdLeverancier)
            DalHelper.VoegParameterToe(cm1, row.IsLeeggoed)
            DalHelper.VoegParameterToe(cm1, row.IsCheque)
            DalHelper.VoegParameterToe(cm1, row.IdCategorie)
            DalHelper.VoegParameterToe(cm1, row.VerwachteVoorraad)
            DalHelper.VoegParameterToe(cm1, row.KortingLeverancierAsObject())
            ' DalHelper.VoegParameterToe(cm1, DBNull.Value) ' KortingLeverancier is altijd null (NIET MEER!), maar anders voegt hij 0 toe, en krijg je concurrencyfouten
            ' DalHelper.VoegParameterToe(cm1, row.DatumToegevoegd) ' WERKT NIET ??? (data type mismatch)
            Dim aantalToegevoegd As Integer = cm1.ExecuteNonQuery()
            If (aantalToegevoegd = 1) Then
                GetNewIdentity(conn, row)
                ' DatumToegevoegd zit niet meer in de dataset omdat dit altijd problemen geeft => code hieronder weg
                ' We gaan ervan uit dat altijd hier toegevoegd wordt, en hier wordt DatumToegevoegd ingesteld via SQL
                ' In het programma wordt het nooit gebruikt, het wordt opgeslagen als extra info.
                '' omdat de datum nu mogelijk niet meer overeenstemt met de dataset, deze ook opnieuw ophalen
                '' anders kan je DBConcurrencyException krijgen
                'Dim cm As New OleDbCommand(String.Format("SELECT DatumToegevoegd FROM Artikels WHERE id={0}", row.Id), conn)
                'row.DatumToegevoegd = CDate(cm.ExecuteScalar()) 
                'row.AcceptChanges()
            Else
                'TODO: error tonen?
            End If
        Finally
            conn.Close()
        End Try
    End Sub

#End Region

#Region "Voorraadbewegingen"

    ''' <summary> 
    ''' Wordt alleen uitgevoerd voor speciale voorraadbewegingen (vervallen of kapotte artikels, eigen verbruik).
    ''' Ook bij telling (inventaris).
    ''' Maar niet bij verkopen en leveringen.
    ''' </summary>
    ''' <param name="row"></param>
    Public Shared Sub VoorraadBewegingToevoegen(ByVal row As ArtikelsDataSet.VoorraadbewegingenRow)
        ' nodig omdat de nieuwe ID anders niet opgehaald wordt.
        ' als je dan daarna nog eens bewaart, krijg je een fout
        Dim conn As New OleDbConnection(My.Settings.fairshopConnectionString)
        Try
            conn.Open()
            Dim strSQL As String = "INSERT INTO `Voorraadbewegingen` (`IdArtikel`, `Datum`, `Aantal`, `Reden`, `Inkoopprijs`) " & _
                "VALUES (?, NOW(), ?, ?, ?)"
            Dim cm1 As New OleDbCommand(strSQL, conn)
            ' let op: volgorde moet dezelfde zijn als hierboven
            DalHelper.VoegParameterToe(cm1, row.IdArtikel)
            ' DalHelper.VoegParameterToe(cm1, row.Datum) ' lukt met datum alleen, maar niet met datum en tijd???
            DalHelper.VoegParameterToe(cm1, row.Aantal)
            DalHelper.VoegParameterToe(cm1, row.Reden)
            DalHelper.VoegParameterToe(cm1, row.Inkoopprijs)
            Dim aantalToegevoegd As Integer = cm1.ExecuteNonQuery()
            If (aantalToegevoegd = 1) Then
                'Dim cm2 As New OleDbCommand("SELECT @@IDENTITY FROM Voorraadbewegingen", conn)
                'Dim newId As Object = cm2.ExecuteScalar()
                'row.Id = Convert.ToInt32(newId)
                'row.AcceptChanges()
                GetNewIdentity(conn, row)

                ' ook voorraad van artikel bijwerken in db én in de dataset
                Dim cm3 As New OleDbCommand("UPDATE Artikels SET VerwachteVoorraad = VerwachteVoorraad - ? WHERE Id = ?", conn)
                DalHelper.VoegParameterToe(cm3, row.Aantal)
                DalHelper.VoegParameterToe(cm3, row.IdArtikel)
                cm3.ExecuteNonQuery()
                row.ArtikelsRow.VerwachteVoorraad -= row.Aantal
                row.ArtikelsRow.AcceptChanges()
            Else
                'TODO: error tonen?
            End If
        Finally
            conn.Close()
        End Try
    End Sub

    ''' <summary>
    ''' Wordt alleen uitgevoerd voor speciale voorraadbewegingen (vervallen of kapotte artikels, eigen verbruik).
    ''' Maar niet bij verkopen en leveringen.
    ''' </summary>
    ''' <param name="row"></param>
    Public Shared Sub VoorraadBewegingBijwerken(ByVal row As ArtikelsDataSet.VoorraadbewegingenRow)
        Dim conn As New OleDbConnection(My.Settings.fairshopConnectionString)
        Try
            conn.Open()
            Dim strSQL As String = "UPDATE `Voorraadbewegingen` SET `IdArtikel`=?, `Aantal`=?, `Reden`=?, `Inkoopprijs`=? " & _
                "WHERE ID=?"
            Dim cm1 As New OleDbCommand(strSQL, conn)
            ' let op: volgorde moet dezelfde zijn als hierboven
            DalHelper.VoegParameterToe(cm1, row.IdArtikel)
            ' DalHelper.VoegParameterToe(cm1, row.Datum)
            DalHelper.VoegParameterToe(cm1, row.Aantal)
            DalHelper.VoegParameterToe(cm1, row.Reden)
            DalHelper.VoegParameterToe(cm1, row.Inkoopprijs)
            DalHelper.VoegParameterToe(cm1, row.Id)
            Dim aantalBijgewerkt As Integer = cm1.ExecuteNonQuery()
            If (aantalBijgewerkt = 1) Then
                Dim oorspronkelijkAantal As Integer = Convert.ToInt32(row.Item("Aantal", DataRowVersion.Original))
                row.AcceptChanges()

                ' pas ook de voorraad aan
                Dim cm3 As New OleDbCommand("UPDATE Artikels SET VerwachteVoorraad = VerwachteVoorraad - ? WHERE Id = ?", conn)
                DalHelper.VoegParameterToe(cm3, row.Aantal - oorspronkelijkAantal)
                DalHelper.VoegParameterToe(cm3, row.IdArtikel)
                cm3.ExecuteNonQuery()
                row.ArtikelsRow.VerwachteVoorraad -= (row.Aantal - oorspronkelijkAantal)
                row.ArtikelsRow.AcceptChanges()
            Else
                'TODO: error tonen?
            End If
        Finally
            conn.Close()
        End Try
    End Sub

#End Region

#Region "Categorieën"

    Public Shared Sub CategorieToevoegen(ByVal row As ArtikelsDataSet.CategorieenRow)
        ' nodig omdat de nieuwe ID anders niet opgehaald wordt.
        ' als je dan daarna nog eens bewaart, krijg je een fout
        Dim conn As New OleDbConnection(My.Settings.fairshopConnectionString)
        Try
            conn.Open()
            Dim strSQL As String = "INSERT INTO Categorieen (Categorie, SubCategorie) VALUES (?, ?)"
            Dim cm1 As New OleDbCommand(strSQL, conn)
            If (row.IsCategorieNull) Then
                DalHelper.VoegParameterToe(cm1, DBNull.Value)
            Else
                DalHelper.VoegParameterToe(cm1, row.Categorie)
            End If
            If (row.IsSubcategorieNull) Then
                DalHelper.VoegParameterToe(cm1, DBNull.Value)
            Else
                DalHelper.VoegParameterToe(cm1, row.Subcategorie)
            End If
            Dim aantalToegevoegd As Integer = cm1.ExecuteNonQuery()
            If (aantalToegevoegd = 1) Then
                'Dim cm2 As New OleDbCommand("SELECT @@IDENTITY FROM Categorieen", conn)
                'Dim newId As Object = cm2.ExecuteScalar()
                'row.Id = Convert.ToInt32(newId)
                'row.AcceptChanges()
                GetNewIdentity(conn, row)
            Else
                'TODO: error tonen?
            End If
        Finally
            conn.Close()
        End Try
    End Sub

#End Region

#Region "Winkeliers"

    Public Shared Sub WinkelierToevoegen(ByVal row As ArtikelsDataSet.WinkeliersRow)
        ' nodig omdat de nieuwe ID anders niet opgehaald wordt.
        ' als je dan daarna nog eens bewaart, krijg je een fout
        Dim conn As New OleDbConnection(My.Settings.fairshopConnectionString)
        Try
            conn.Open()
            Dim strSQL As String = "INSERT INTO Winkeliers (Naam, Wachtwoord) VALUES (?, ?)"
            Dim cm1 As New OleDbCommand(strSQL, conn)
            DalHelper.VoegParameterToe(cm1, row.Naam)
            DalHelper.VoegParameterToe(cm1, row.Wachtwoord)
            Dim aantalToegevoegd As Integer = cm1.ExecuteNonQuery()
            If (aantalToegevoegd = 1) Then
                'Dim cm2 As New OleDbCommand("SELECT @@IDENTITY FROM Winkeliers", conn)
                'Dim newId As Object = cm2.ExecuteScalar()
                'row.Id = Convert.ToInt32(newId)
                'row.AcceptChanges()
                GetNewIdentity(conn, row)
            Else
                'TODO: error tonen?
            End If
        Finally
            conn.Close()
        End Try
    End Sub

#End Region

#Region "Leveranciers"

    Public Shared Sub LeverancierToevoegen(ByVal row As ArtikelsDataSet.LeveranciersRow)
        ' nodig omdat de nieuwe ID anders niet opgehaald wordt.
        ' als je dan daarna nog eens bewaart, krijg je een fout
        Dim conn As New OleDbConnection(My.Settings.fairshopConnectionString)
        Try
            conn.Open()
            Dim strSQL As String = "INSERT INTO Leveranciers (Naam) VALUES (?)"
            Dim cm1 As New OleDbCommand(strSQL, conn)
            DalHelper.VoegParameterToe(cm1, row.Naam)
            Dim aantalToegevoegd As Integer = cm1.ExecuteNonQuery()
            If (aantalToegevoegd = 1) Then
                'Dim cm2 As New OleDbCommand("SELECT @@IDENTITY FROM Leveranciers", conn)
                'Dim newId As Object = cm2.ExecuteScalar()
                'row.Id = Convert.ToInt32(newId)
                'row.AcceptChanges()
                GetNewIdentity(conn, row)
            Else
                'TODO: error tonen?
            End If
        Finally
            conn.Close()
        End Try
    End Sub

#End Region

#Region "Klanten"

    Public Shared Sub KlantToevoegen(ByVal row As ArtikelsDataSet.KlantenRow)
        ' nodig omdat de nieuwe ID anders niet opgehaald wordt.
        ' als je dan daarna nog eens bewaart, krijg je een fout
        Dim conn As New OleDbConnection(My.Settings.fairshopConnectionString)
        Try
            conn.Open()
            Dim strSQL As String = "INSERT INTO Klanten " & _
                "(Naam, Adres, Postcode, Gemeente, Telefoon, Email, Klantenkaart, BTWnummer) " & _
                "VALUES (?, ?, ?, ?, ?, ?, ?, ?)"
            Dim cm1 As New OleDbCommand(strSQL, conn)
            DalHelper.VoegParameterToe(cm1, row.Naam)
            DalHelper.VoegParameterToe(cm1, row.Adres)
            DalHelper.VoegParameterToe(cm1, row.Postcode)
            DalHelper.VoegParameterToe(cm1, row.Gemeente)
            DalHelper.VoegParameterToe(cm1, row.Telefoon)
            DalHelper.VoegParameterToe(cm1, row.Email)
            DalHelper.VoegParameterToe(cm1, row.Klantenkaart)
            DalHelper.VoegParameterToe(cm1, row.BTWNummer)
            Dim aantalToegevoegd As Integer = cm1.ExecuteNonQuery()
            If (aantalToegevoegd = 1) Then
                'Dim cm2 As New OleDbCommand("SELECT @@IDENTITY FROM Klanten", conn)
                'Dim newId As Object = cm2.ExecuteScalar()
                'row.Id = Convert.ToInt32(newId)
                'row.AcceptChanges()
                GetNewIdentity(conn, row)
            Else
                'TODO: error tonen?
            End If
        Finally
            conn.Close()
        End Try
    End Sub

#End Region

#Region "Verkopen"

    ''' <summary>
    ''' Gebruikt vanuit tools om verkoop op te halen uit een andere databank
    ''' </summary>
    ''' <param name="ds"></param>
    ''' <param name="databaseBestand"></param>
    Public Shared Sub VerkoopOphalen(ByVal ds As ArtikelsDataSet, ByVal databaseBestand As String)
        Dim strConnSource As String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & databaseBestand
        Using conn As New OleDbConnection(strConnSource)
            Dim winkeliersAdapter As New ArtikelsDataSetTableAdapters.WinkeliersTableAdapter()
            winkeliersAdapter.Connection = conn
            winkeliersAdapter.Fill(ds.Winkeliers)
            Dim verkoopsoortenAdapter As New ArtikelsDataSetTableAdapters.VerkoopsoortenTableAdapter()
            verkoopsoortenAdapter.Connection = conn
            verkoopsoortenAdapter.Fill(ds.Verkoopsoorten)
            Dim klantenAdapter As New ArtikelsDataSetTableAdapters.KlantenTableAdapter()
            klantenAdapter.Connection = conn
            klantenAdapter.Fill(ds.Klanten)
            Dim verkopenAdapter As New ArtikelsDataSetTableAdapters.VerkopenTableAdapter()
            verkopenAdapter.Connection = conn
            verkopenAdapter.Fill(ds.Verkopen)
            Dim VerkoopsDetailsAdapter As New ArtikelsDataSetTableAdapters.VerkoopsDetailsTableAdapter()
            VerkoopsDetailsAdapter.Connection = conn
            VerkoopsDetailsAdapter.Fill(ds.VerkoopsDetails)
        End Using
    End Sub

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <param name="row"></param>
    ''' <returns>Aantal toegevoegde verkopen (0 of 1)</returns>
    ''' <remarks></remarks>
    Public Shared Function VerkoopToevoegen(ByVal row As ArtikelsDataSet.VerkopenRow) As Integer
        ' nodig omdat de nieuwe ID anders niet opgehaald wordt.
        ' als je dan daarna nog eens bewaart, krijg je een fout
        Using conn As New OleDbConnection(My.Settings.fairshopConnectionString)
            conn.Open()

            ' haal eerst het kortingspercentage van de klant op. Dit wordt bij de verkoop bijgehouden voor het
            ' geval het kortingspercentage van de klant later ooit zou veranderen.
            Dim cm1 As New OleDbCommand("SELECT Kortingspercentage FROM Klanten WHERE ID=?", conn)
            cm1.Parameters.AddWithValue("ID", row.IdKlant)
            Dim objKortingspercentage As Object = cm1.ExecuteScalar()
            If (objKortingspercentage IsNot Nothing AndAlso Not IsDBNull(objKortingspercentage)) Then
                row.Kortingspercentage = Convert.ToDecimal(objKortingspercentage)
            End If

            Dim strSQL As String = "INSERT INTO `Verkopen` " & _
                "(`Datum`, `Tijd`, `IdKlant`, `CashBetaald`, `IdWinkelier`, `IdSoort`, " & _
                "`Begintotaal`, `Eindtotaal`, `CommentaarBegintotaal`, `CommentaarEindtotaal`, " & _
                "`InUitKasBedrag`, `InUitKasReden`, `NaarBankBedrag`, `NaarBankNaam`, `NaarBankReferentie`, " & _
                "`Factuurnummer`, `IsFactuurBehandeld`, `Omschrijving`, `Kortingspercentage`, `Consignatie`, " & _
                "`BedragBancontact`, `BedragMaaltijdcheques`) " & _
                "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
            Dim cm2 As New OleDbCommand(strSQL, conn)
            ' let op: volgorde moet dezelfde zijn als hierboven
            DalHelper.VoegParameterToe(cm2, row.Datum)
            DalHelper.VoegParameterToe(cm2, row.Tijd)
            DalHelper.VoegParameterToe(cm2, row.IdKlant)
            DalHelper.VoegParameterToe(cm2, row.CashBetaald)
            DalHelper.VoegParameterToe(cm2, row.IdWinkelier)
            DalHelper.VoegParameterToe(cm2, row.IdSoort)
            DalHelper.VoegParameterToe(cm2, row.Begintotaal)
            DalHelper.VoegParameterToe(cm2, row.Eindtotaal)
            DalHelper.VoegParameterToe(cm2, row.CommentaarBegintotaal)
            DalHelper.VoegParameterToe(cm2, row.CommentaarEindtotaal)
            DalHelper.VoegParameterToe(cm2, row.InUitKasBedrag)
            DalHelper.VoegParameterToe(cm2, row.InUitKasReden)
            DalHelper.VoegParameterToe(cm2, row.NaarBankBedrag)
            DalHelper.VoegParameterToe(cm2, row.NaarBankNaam)
            DalHelper.VoegParameterToe(cm2, row.NaarBankReferentie)
            DalHelper.VoegParameterToe(cm2, row.FactuurNummer)
            DalHelper.VoegParameterToe(cm2, row.IsFactuurBehandeld)
            DalHelper.VoegParameterToe(cm2, row.Omschrijving)
            DalHelper.VoegParameterToe(cm2, row.Kortingspercentage)
            DalHelper.VoegParameterToe(cm2, row.Consignatie)
            DalHelper.VoegParameterToe(cm2, row.BedragBancontact)
            DalHelper.VoegParameterToe(cm2, row.BedragMaaltijdcheques)

            Dim aantalToegevoegd As Integer = cm2.ExecuteNonQuery()
            If (aantalToegevoegd = 1) Then
                'Dim cm3 As New OleDbCommand("SELECT @@IDENTITY FROM Verkopen", conn)
                'Dim newId As Object = cm3.ExecuteScalar()
                'row.Id = Convert.ToInt32(newId)
                'row.AcceptChanges()
                GetNewIdentity(conn, row)
                Return 1
            Else
                'TODO: error tonen?
                Return 0
            End If
        End Using
    End Function

#End Region

#Region "Verkoopsdetails"

    Public Shared Sub VerkoopsDetailsToevoegen(ByVal row As ArtikelsDataSet.VerkoopsDetailsRow)
        ' nodig omdat de nieuwe ID anders niet opgehaald wordt.
        ' als je dan daarna nog eens bewaart, krijg je een fout
        Using conn As New OleDbConnection(My.Settings.fairshopConnectionString)
            conn.Open()
            Dim strSQL As String = "INSERT INTO VerkoopsDetails " & _
                "(IdVerkoop, IdArtikel, Prijs, StatiegeldEuro, Aantal, VolgnummerKlant, ExtraOmschrijving, " & _
                "Bancontact, Maaltijdcheque) " & _
                "VALUES (?,?,?,?,?,?,?,?,?)"
            Dim cm1 As New OleDbCommand(strSQL, conn)
            ' let op: volgorde moet dezelfde zijn als hierboven
            DalHelper.VoegParameterToe(cm1, row.IdVerkoop)
            DalHelper.VoegParameterToe(cm1, row.IdArtikel)
            DalHelper.VoegParameterToe(cm1, row.Prijs)
            DalHelper.VoegParameterToe(cm1, row.StatiegeldEuro)
            DalHelper.VoegParameterToe(cm1, row.Aantal)
            DalHelper.VoegParameterToe(cm1, row.VolgnummerKlant)
            DalHelper.VoegParameterToe(cm1, row.ExtraOmschrijving)
            If (row.IsBancontactNull) Then
                row.Bancontact = False
            End If
            DalHelper.VoegParameterToe(cm1, row.Bancontact)
            If (row.IsMaaltijdchequeNull) Then
                row.Maaltijdcheque = False
            End If
            DalHelper.VoegParameterToe(cm1, row.Maaltijdcheque)

            Dim aantalToegevoegd As Integer = cm1.ExecuteNonQuery()
            If (aantalToegevoegd = 1) Then
                'Dim cm2 As New OleDbCommand("SELECT @@IDENTITY FROM VerkoopsDetails", conn)
                'Dim newId As Object = cm2.ExecuteScalar()
                'row.Id = Convert.ToInt32(newId)
                'row.AcceptChanges()
                GetNewIdentity(conn, row)
                Return
            Else
                'TODO: error tonen?
            End If
        End Using
    End Sub

    ''' <summary>
    ''' Bewaar de details van de verkoop en pas de voorraad in de Artikels-tabel aan.
    ''' </summary>
    ''' <param name="verkoopsDetails">array met verkoopsdetails. 
    ''' Let op: dit mogen verkoopsdetails zijn uit een andere dataset dan Utility.Data (alleen in tests wordt dit gedaan)
    ''' Voor het bijwerken van de artikels gebruiken we wel Utility.Data.</param>
    Public Shared Sub VerkoopsDetailsBewaren(ByVal verkoopsDetails() As ArtikelsDataSet.VerkoopsDetailsRow)
        ' pas de voorraad aan met de nieuwe waarden na de verkoop
        For Each verkoopsDetailsRow As ArtikelsDataSet.VerkoopsDetailsRow In verkoopsDetails
            Dim idArtikel As Integer
            If (verkoopsDetailsRow.RowState = DataRowState.Deleted) Then
                idArtikel = Convert.ToInt32(verkoopsDetailsRow.Item("IdArtikel", DataRowVersion.Original))
            Else
                idArtikel = verkoopsDetailsRow.IdArtikel
            End If
            Dim artikelRow As ArtikelsDataSet.ArtikelsRow = Utility.Data.Artikels.FindById(idArtikel)
            Select Case verkoopsDetailsRow.RowState
                Case DataRowState.Added
                    ' eigen methode gebruiken om toe te voegen
                    VerkoopsDetailsToevoegen(verkoopsDetailsRow)
                    artikelRow.VerwachteVoorraad -= verkoopsDetailsRow.Aantal
                Case DataRowState.Deleted
                    Dim oudaantal As Integer = Convert.ToInt32(verkoopsDetailsRow.Item("Aantal", DataRowVersion.Original))
                    artikelRow.VerwachteVoorraad += oudaantal
                Case DataRowState.Modified
                    Dim oudaantal As Integer = Convert.ToInt32(verkoopsDetailsRow.Item("Aantal", DataRowVersion.Original))
                    artikelRow.VerwachteVoorraad -= (verkoopsDetailsRow.Aantal - oudaantal)
                Case DataRowState.Unchanged
                    ' niets doen
                Case DataRowState.Detached
                    Throw New Exception("Onverwachte status van de rij")
            End Select
        Next

        ' we maken hier een ad hoc adapter aan in plaats van de standaard adapter die bij de dataset zit
        ' de reden is dat de standaard adapter niet kan updaten omdat die data van twee tabellen gebruikt
        Dim strSqlSelect As String = "SELECT Id, IdVerkoop, IdArtikel, Prijs, Aantal, VolgnummerKlant, ExtraOmschrijving, ElektronischBetaald " & _
            "FROM VerkoopsDetails"
        Dim detailsAdapter As New OleDbDataAdapter(strSqlSelect, My.Settings.fairshopConnectionString)
        Dim detailsCommandBuilder As New OleDbCommandBuilder(detailsAdapter)
        detailsAdapter.Update(verkoopsDetails)
        Dim artikelsAdapter As New ArtikelsDataSetTableAdapters.ArtikelsTableAdapter
        artikelsAdapter.Update(Utility.Data.Artikels)
    End Sub

    Public Shared Sub VerkoopsDetailsBewarenBijBestaandeLeveringsbon(ByVal verkoop As ArtikelsDataSet.VerkopenRow, _
            ByVal idVerkoopLeveringsbon As Integer, ByVal consignatie As Boolean)
        Dim leveringsbon As ArtikelsDataSet.VerkopenRow = Utility.Data.Verkopen.FindById(idVerkoopLeveringsbon)

        ' consignatie aanpassen
        If (leveringsbon IsNot Nothing) Then
            leveringsbon.Consignatie = consignatie
        End If

        ' niet ganse datatable updaten, maar alleen de rijen die overgezet zijn van de huidige klant
        Dim rowsToUpdate As New List(Of ArtikelsDataSet.VerkoopsDetailsRow)

        ' pas de voorraad aan met de nieuwe waarden na de verkoop
        For i As Integer = verkoop.GetVerkoopsDetailsRows.Count - 1 To 0 Step -1
            Dim verkoopsDetailsRow As ArtikelsDataSet.VerkoopsDetailsRow = verkoop.GetVerkoopsDetailsRows(i)
            ' alleen huidige verkoopsdetails overzetten, niet deze die bv. in pauze staan
            If (verkoopsDetailsRow.Status <> StatusImage.Huidig) Then Continue For

            Dim artikelRow As ArtikelsDataSet.ArtikelsRow = Utility.Data.Artikels.FindById(verkoopsDetailsRow.IdArtikel)
            Dim aantal As Integer = verkoopsDetailsRow.Aantal
            ' we gaan alleen de gewijzigde details bekijken
            Select Case verkoopsDetailsRow.RowState
                Case DataRowState.Added
                    ' Zet de Id expliciet gelijk aan de id van deze rij
                    ' Hiermee worden de verkoopsdetails gekoppeld aan de leveringsbon
                    verkoopsDetailsRow.IdVerkoop = idVerkoopLeveringsbon
                    ' default waarde voor volgnummerklant zelfde voor alle details (ook die later toegevoegd worden)
                    ' wordt gebruikt bij het afdrukken om op te sorteren
                    verkoopsDetailsRow.VolgnummerKlant = 1

                    ' eigen methode gebruiken om toe te voegen
                    VerkoopsDetailsToevoegen(verkoopsDetailsRow)

                    artikelRow.VerwachteVoorraad -= aantal
                Case DataRowState.Deleted ' komt dit voor?
                    artikelRow.VerwachteVoorraad += aantal
                Case DataRowState.Modified ' komt dit voor?
                    Dim oudaantal As Integer = Convert.ToInt32(verkoopsDetailsRow.Item("Aantal", DataRowVersion.Original))
                    artikelRow.VerwachteVoorraad -= (aantal - oudaantal)
                Case DataRowState.Unchanged
                    ' niets doen
                    Continue For
                Case DataRowState.Detached
                    Throw New Exception("Onverwachte status van de rij")
            End Select
            rowsToUpdate.Add(verkoopsDetailsRow)
        Next

        ' we maken hier een ad hoc adapter aan in plaats van de standaard adapter die bij de dataset zit
        ' de reden is dat de standaard adapter niet kan updaten omdat die data van twee tabellen gebruikt
        Dim strSqlSelect As String = "SELECT Id, IdVerkoop, IdArtikel, Prijs, Aantal, VolgnummerKlant, ExtraOmschrijving " & _
            "FROM VerkoopsDetails"
        Dim detailsAdapter As New OleDbDataAdapter(strSqlSelect, My.Settings.fairshopConnectionString)
        Dim detailsCommandBuilder As New OleDbCommandBuilder(detailsAdapter)
        detailsAdapter.Update(rowsToUpdate.ToArray()) ' niet ganse tabel updaten, alleen bepaalde rijen
        Dim artikelsAdapter As New ArtikelsDataSetTableAdapters.ArtikelsTableAdapter
        artikelsAdapter.Update(Utility.Data.Artikels)
        Dim verkopenAdapter As New ArtikelsDataSetTableAdapters.VerkopenTableAdapter
        verkopenAdapter.Update(leveringsbon) ' bijwerken van consignatie-vlag
    End Sub

    ''' <summary>
    ''' Annuleert de verkoopsdetails van een leveringsbon.
    ''' Wordt gebruikt als de klant cash wil betalen.
    ''' De return-waarde bevat een dataset met alleen de verkoopsdetails die dan in een kasblad kunnen ingebracht worden.
    ''' </summary>
    ''' <param name="idVerkoopLeveringsbon"></param>
    ''' <returns>ArtikelsDataset met alleen de VerkoopsDetails-tabel ingevuld</returns>
    Public Shared Function VerkoopsDetailsVanLeveringsbonAnnuleren(ByVal idVerkoopLeveringsbon As Integer) As ArtikelsDataSet
        Dim verkoopsdetailsLeveringsbon As List(Of ArtikelsDataSet.VerkoopsDetailsRow) = _
            (From vdr In Utility.Data.VerkoopsDetails _
            Where vdr.IdVerkoop = idVerkoopLeveringsbon _
            Select vdr) _
            .ToList()

        Dim antiVerkoopsdetails As New List(Of ArtikelsDataSet.VerkoopsDetailsRow)

        Dim kasbladDs As New ArtikelsDataSet
        Dim tempId As Integer = (From vdr In Utility.Data.VerkoopsDetails Select vdr.Id).Min() - 1
        If (tempId > 0) Then tempId = -1
        For Each leveringsbonDetailsRow As ArtikelsDataSet.VerkoopsDetailsRow In verkoopsdetailsLeveringsbon
            ' toevoegen aan dataset
            kasbladDs.VerkoopsDetails.ImportRow(leveringsbonDetailsRow)
            ' tegengestelde verkoopsdetail toevoegen op leveringsbon (nuloperatie maken)
            Dim antiDetail As ArtikelsDataSet.VerkoopsDetailsRow = Utility.Data.VerkoopsDetails.NewVerkoopsDetailsRow()
            antiDetail.ItemArray = leveringsbonDetailsRow.ItemArray
            antiDetail.Aantal = -leveringsbonDetailsRow.Aantal ' tegengesteld aantal
            antiDetail.Id = tempId
            Utility.Data.VerkoopsDetails.AddVerkoopsDetailsRow(antiDetail)
            antiVerkoopsdetails.Add(antiDetail)
            tempId -= 1
        Next
        ' toegevoegde verkoopsdetails bewaren
        VerkoopsDetailsBewaren(antiVerkoopsdetails.ToArray())

        ' leveringsbon op "IsFactuurBehandeld=True" zetten, zodat hij niet meer in de lijst met leveringsbons om uit te kiezen komt.
        Dim leveringsbonVerkoop As ArtikelsDataSet.VerkopenRow = Utility.Data.Verkopen.FindById(idVerkoopLeveringsbon)
        leveringsbonVerkoop.IsFactuurBehandeld = True
        Dim verkopenAdapter As New ArtikelsDataSetTableAdapters.VerkopenTableAdapter
        verkopenAdapter.Update(leveringsbonVerkoop)

        ' loggen
        log.WriteInfo(String.Format("Leveringsbon {0} werd geannuleerd en de artikels werden toegevoegd aan een gewone verkoop", idVerkoopLeveringsbon))
        ' dataset teruggeven
        Return kasbladDs
    End Function

#End Region

#Region "Leveringen"

    ''' <summary>
    ''' Levering ophalen.
    ''' </summary>
    ''' <param name="dt">Datatable waar de leveringsdetails toegevoegd worden in de artikels-tabel</param>
    ''' <param name="idLevering">ID van de levering</param>
    Public Shared Sub LeveringOphalen(ByVal dt As ArtikelsDataSet.ArtikelsDataTable, ByVal idLevering As Integer)
        Dim huidigeVoorraad As New ArtikelsDataSet

        Dim artikelsAdapter As New ArtikelsDataSetTableAdapters.ArtikelsTableAdapter
        artikelsAdapter.Fill(huidigeVoorraad.Artikels)

        ' haal huidige gegevens van levering op
        Dim leveringenAdapter As New ArtikelsDataSetTableAdapters.LeveringenTableAdapter
        leveringenAdapter.FillById(huidigeVoorraad.Leveringen, idLevering)
        Dim detailsAdapter As New ArtikelsDataSetTableAdapters.LeveringDetailsTableAdapter
        detailsAdapter.FillByIdLevering(huidigeVoorraad.LeveringDetails, idLevering)

        dt.Clear()
        For Each leveringDetailsRow As ArtikelsDataSet.LeveringDetailsRow In huidigeVoorraad.LeveringDetails
            Dim aantal As Integer = leveringDetailsRow.Aantal
            Dim idArtikel As Integer = leveringDetailsRow.IdArtikel
            Dim artikelsRow As ArtikelsDataSet.ArtikelsRow = huidigeVoorraad.Artikels.FindById(idArtikel)
            ' toon niet de echte voorraad, maar het aantal uit de levering
            artikelsRow.Voorraad = leveringDetailsRow.Aantal
            ' voeg de rij toe aan de tabel die we willen tonen
            dt.Rows.Add(artikelsRow.ItemArray)
        Next
        dt.AcceptChanges()
    End Sub

    ''' <summary>
    ''' Gebruikt vanuit tools om levering op te halen uit een andere databank
    ''' </summary>
    ''' <param name="ds"></param>
    ''' <param name="databaseBestand"></param>
    Public Shared Sub LeveringOphalen(ByVal ds As ArtikelsDataSet, ByVal databaseBestand As String)
        Dim strConnSource As String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & databaseBestand
        Using conn As New OleDbConnection(strConnSource)
            Dim leveranciersAdapter As New ArtikelsDataSetTableAdapters.LeveranciersTableAdapter()
            leveranciersAdapter.Connection = conn
            leveranciersAdapter.Fill(ds.Leveranciers)
            Dim leveringenAdapter As New ArtikelsDataSetTableAdapters.LeveringenTableAdapter()
            leveringenAdapter.Connection = conn
            leveringenAdapter.Fill(ds.Leveringen)
        End Using
    End Sub

    Public Shared Sub LeveringToevoegen(ByVal row As ArtikelsDataSet.LeveringenRow)
        ' nodig omdat de nieuwe ID anders niet opgehaald wordt.
        ' als je dan daarna nog eens bewaart, krijg je een fout
        Dim conn As New OleDbConnection(My.Settings.fairshopConnectionString)
        Try
            conn.Open()
            Dim strSQL As String = "INSERT INTO `Leveringen` (`Datum`, `IdLeverancier`, `Factuurnummer`) " & _
                "VALUES (?, ?, ?)"
            Dim cm1 As New OleDbCommand(strSQL, conn)
            ' let op: volgorde moet dezelfde zijn als hierboven
            DalHelper.VoegParameterToe(cm1, row.Datum)
            DalHelper.VoegParameterToe(cm1, row.IdLeverancier)
            DalHelper.VoegParameterToe(cm1, row.Factuurnummer)
            Dim aantalToegevoegd As Integer = cm1.ExecuteNonQuery()
            If (aantalToegevoegd = 1) Then
                'Dim cm2 As New OleDbCommand("SELECT @@IDENTITY FROM Leveringen", conn)
                'Dim newId As Object = cm2.ExecuteScalar()
                'row.Id = Convert.ToInt32(newId)
                'row.AcceptChanges()
                GetNewIdentity(conn, row)
            Else
                'TODO: error tonen?
            End If
        Finally
            conn.Close()
        End Try
    End Sub

    ''' <summary>
    ''' Bewaar de levering, de details van de levering en pas de voorraad in de Artikels-tabel aan.
    ''' </summary>
    ''' <param name="leveringRij">Rij van de levering, komt uit Utility.Data</param>
    ''' <param name="tabelLevering">Tabel met artikels, stelt de leveringdetails voor. Komt NIET uit Utility.Data</param>
    Public Shared Sub LeveringBewaren(ByVal leveringRij As ArtikelsDataSet.LeveringenRow, _
            ByVal tabelLevering As ArtikelsDataSet.ArtikelsDataTable)
        ' bij een levering wordt een lijst met artikels opgevuld
        ' (de reden dat we niet een lijst met leveringsdetails opvullen, maar wel een lijst met artikels
        ' is omdat we dan gemakkelijker nieuwe artikels kunnen toevoegen en bestaande artikels aanpassen)
        ' de ingevulde voorraad is niet de echte voorraad, maar het aantal geleverd
        ' doe hier de omzetting vooraleer te bewaren naar de tabel met LeveringDetails

        Dim huidigeVoorraad As ArtikelsDataSet = Utility.Data

        ' stap 1: levering zelf updaten
        If (leveringRij.RowState = DataRowState.Modified) Then
            Dim leveringenAdapter As New ArtikelsDataSetTableAdapters.LeveringenTableAdapter
            leveringenAdapter.Update(leveringRij)
        End If

        ' stap 2: mogelijk zijn er nieuwe artikels toegevoegd 
        '         voeg deze eerst toe in de databanktabel Artikels
        Dim artikelsAdapter As New ArtikelsDataSetTableAdapters.ArtikelsTableAdapter
        Dim tempArtikels As New ArtikelsDataSet()
        For Each row As ArtikelsDataSet.ArtikelsRow In tabelLevering.Rows
            Dim geleverdArtikelId As Integer = row.Id
            'If row.RowState = DataRowState.Added Then ' mag niet, ALLE artikels in de leveringsdataset zijn Added!
            If Not (From a In huidigeVoorraad.Artikels _
                Where a.Id = geleverdArtikelId).Any Then
                ' In het scherm om nieuwe artikels toe te voegen wordt de voorraad ingesteld (zoals bij een Inventaris)
                ' Laat deze echter op 0 in de tabel artikels.
                ' De waarde moet in het veld "VerwachteVoorraad" van het artikel komen, maar dat gebeurt hierna in stap 4
                Dim aantalGeleverd As Integer = row.Voorraad
                row.VerwachteVoorraad = 0
                row.Voorraad = 0
                row.Verkoopbaar = True
                ArtikelToevoegen(row)
                row.Voorraad = aantalGeleverd ' herstel om later met de levering verder te kunnen doen
                row.AcceptChanges()
                ' artikel ophalen in temp dataset
                artikelsAdapter.FillById(tempArtikels.Artikels, row.Id)
                ' artikel ook in Utility.Data in memory toevoegen
                Utility.Data.Merge(tempArtikels)
            End If
            'End If
        Next

        ' stap 3: alle vorige leveringsdetails van deze levering ongedaan maken
        '         rijen verwijderen uit LeveringDetails
        '         voorraad aanpassen
        For Each leveringDetailsRow As ArtikelsDataSet.LeveringDetailsRow In leveringRij.GetLeveringDetailsRows()
            Dim aantal As Integer = leveringDetailsRow.Aantal
            Dim idArtikel As Integer = leveringDetailsRow.IdArtikel
            leveringDetailsRow.Delete()
            Dim artikelRow As ArtikelsDataSet.ArtikelsRow = huidigeVoorraad.Artikels.FindById(idArtikel)
            ' herstel de VerwachteVoorraad
            artikelRow.VerwachteVoorraad -= aantal
        Next
        ' databank bijwerken met adapter.Update werkt hier niet omdat de leveringdetails geen up-to-date id hebben (deze is nog negatief)
        ' we doen niet de moeite om die id telkens up-to-date te houden omdat we de rij zelf via de id toch nooit updaten 
        ' alleen hier bij het verwijderen moeten we er dan wel rekening mee houden
        LeveringLeegmaken(leveringRij.Id)               ' verwijderen op de databank
        huidigeVoorraad.LeveringDetails.AcceptChanges() ' verwijderen op de datatable

        ' stap 4: nieuwe details van de levering inbrengen
        For Each leveringDetailsRow As ArtikelsDataSet.ArtikelsRow In tabelLevering.Rows
            ' rij toevoegen aan LeveringDetails
            Dim artikelRow As ArtikelsDataSet.ArtikelsRow = huidigeVoorraad.Artikels.FindById(leveringDetailsRow.Id)
            Dim aantal As Integer = leveringDetailsRow.Voorraad
            Dim korting As Double = If(leveringDetailsRow.IsKortingLeverancierNull(), 0D, leveringDetailsRow.KortingLeverancier)
            Dim newrow As ArtikelsDataSet.LeveringDetailsRow = _
                huidigeVoorraad.LeveringDetails.AddLeveringDetailsRow(leveringRij, artikelRow, aantal, korting)
            ' pas de VerwachteVoorraad aan met het nieuwe geleverde aantal
            artikelRow.VerwachteVoorraad += aantal
        Next

        ' toegevoegde records bijwerken op de databank
        Dim detailsAdapter As New ArtikelsDataSetTableAdapters.LeveringDetailsTableAdapter
        detailsAdapter.Update(huidigeVoorraad.LeveringDetails)

        artikelsAdapter.Update(huidigeVoorraad.Artikels)

        tabelLevering.AcceptChanges()

    End Sub

    Public Shared Sub LeveringLeegmaken(ByVal idLevering As Integer)
        Dim conn As New OleDbConnection(My.Settings.fairshopConnectionString)
        Try
            conn.Open()
            Dim strSQL As String = "DELETE FROM leveringdetails WHERE idLevering = ?"
            Dim cm As New OleDbCommand(strSQL, conn)
            DalHelper.VoegParameterToe(cm, idLevering)
            cm.ExecuteNonQuery()
        Finally
            conn.Close()
        End Try
    End Sub

#End Region

#Region "Meldingen"

    Public Shared Sub MeldingToevoegen(ByVal row As ArtikelsDataSet.MeldingenRow)
        ' nodig omdat de nieuwe ID anders niet opgehaald wordt.
        ' als je dan daarna nog eens bewaart, krijg je een fout
        Dim conn As New OleDbConnection(My.Settings.fairshopConnectionString)
        Try
            conn.Open()
            Dim strSQL As String = "INSERT INTO `Meldingen` (`Melding`) " & _
                "VALUES (?)"
            Dim cm1 As New OleDbCommand(strSQL, conn)
            ' let op: volgorde moet dezelfde zijn als hierboven
            DalHelper.VoegParameterToe(cm1, row.Melding)
            Dim aantalToegevoegd As Integer = cm1.ExecuteNonQuery()
            If (aantalToegevoegd = 1) Then
                'Dim cm2 As New OleDbCommand("SELECT @@IDENTITY FROM Leveringen", conn)
                'Dim newId As Object = cm2.ExecuteScalar()
                'row.Id = Convert.ToInt32(newId)
                'row.AcceptChanges()
                GetNewIdentity(conn, row)
            Else
                'TODO: error tonen?
            End If
        Finally
            conn.Close()
        End Try
    End Sub

#End Region

#Region "Onbekende barcodes"

    Public Shared Function OnbekendeBarcodeToevoegen(ByVal barcode As String) As Boolean
        Dim conn As New OleDbConnection(My.Settings.fairshopConnectionString)
        Try
            conn.Open()
            Dim strSQL As String = "INSERT INTO NietHerkendeBarcodes (Barcode, TijdstipIngescand) " & _
                "VALUES ( ?, ? )"
            Dim cm As New OleDbCommand(strSQL, conn)
            ' let op: volgorde moet dezelfde zijn als hierboven
            cm.Parameters.AddWithValue("?", barcode)

            'cm.Parameters.AddWithValue("?", DateTime.Now()) ' Werkt niet ?
            Dim paramTijdstipIngescand As New OleDbParameter("TijdstipIngescand", OleDbType.Date)
            paramTijdstipIngescand.Value = DateTime.Now()
            cm.Parameters.Add(paramTijdstipIngescand)

            Dim aantal As Integer = cm.ExecuteNonQuery()
            Return aantal = 1
        Catch ex As Exception
            ' alleen loggen, exception inslikken
            log.WriteError(ex.ToString())
        Finally
            conn.Close()
        End Try
        Return False
    End Function

#End Region

#Region "Dubbele barcodes"

    Public Shared Sub UpdateData()
        Dim conn As New OleDbConnection(My.Settings.fairshopConnectionString)
        Try
            conn.Open()
            ' we maken hier een ad hoc adapter aan in plaats van de standaard adapter die bij de dataset zit
            ' de reden is dat de standaard adapter niet kan updaten omdat die data van twee tabellen gebruikt
            Dim strSqlSelect As String = "SELECT Id, IdArtikel FROM VerkoopsDetails" ' alleen IdArtikel moet geüpdatet worden
            Dim verkoopsdetailsAdapter As New OleDbDataAdapter(strSqlSelect, conn)
            Dim detailsCommandBuilder As New OleDbCommandBuilder(verkoopsdetailsAdapter)
            verkoopsdetailsAdapter.Update(Utility.Data.VerkoopsDetails)

            Dim leveringdetailsAdapter As New ArtikelsDataSetTableAdapters.LeveringDetailsTableAdapter
            leveringdetailsAdapter.Update(Utility.Data.LeveringDetails)

            Dim voorraadbewegingenAdapter As New ArtikelsDataSetTableAdapters.VoorraadbewegingenTableAdapter
            voorraadbewegingenAdapter.Update(Utility.Data.Voorraadbewegingen)

            ' adapter geeft steeds "Concurrency violation: the UpdateCommand affected 0 of the expected 1 records."
            'Dim samengesteldeArtikelsAdapter As New SamengesteldeArtikelsDataSetTableAdapters.SamengesteldeArtikelsTableAdapter
            'samengesteldeArtikelsAdapter.Update(Utility.SamengesteldeArtikels)
            Dim gewijzigdeSamengesteldeArtikels As DataTable = Utility.SamengesteldeArtikels.GetChanges()
            If (gewijzigdeSamengesteldeArtikels IsNot Nothing) Then
                For Each sa As SamengesteldeArtikelsDataSet.SamengesteldeArtikelsRow In DirectCast(gewijzigdeSamengesteldeArtikels, SamengesteldeArtikelsDataSet.SamengesteldeArtikelsDataTable)
                    Dim strUpdate As String = "UPDATE SamengesteldeArtikels SET ArtikelId = ?, DeelArtikelId = ? WHERE Id = ?"
                    Dim cm As New OleDbCommand(strUpdate, conn)
                    cm.Parameters.AddWithValue("?", sa.ArtikelId)
                    cm.Parameters.AddWithValue("?", sa.DeelArtikelId)
                    cm.Parameters.AddWithValue("?", sa.Id)
                    cm.ExecuteNonQuery()
                    sa.AcceptChanges()
                Next
            End If

            Dim artikelsAdapter As New ArtikelsDataSetTableAdapters.ArtikelsTableAdapter
            artikelsAdapter.Update(Utility.Data.Artikels)
        Finally
            conn.Close()
        End Try
    End Sub

#End Region

#Region "Historiek"

    Public Shared Function GetArtikelHistoriek(ByVal idArtikel As Integer, ByVal startDatum As Date) As HistoriekDataSet
        Dim conn As New OleDbConnection(My.Settings.fairshopConnectionString)
        Try
            conn.Open()
            Dim strSQL1 As String = "SELECT Verkopen.Datum, ""Verkoop"" AS Naam, - VerkoopsDetails.Aantal AS Waarde " & _
                "FROM Verkopen INNER JOIN VerkoopsDetails ON Verkopen.Id = VerkoopsDetails.IdVerkoop " & _
                "WHERE VerkoopsDetails.IdArtikel = @ID AND Verkopen.Datum >= @Datum"
            Dim cm1 As New OleDbCommand(strSQL1, conn)
            cm1.Parameters.AddWithValue("ID", idArtikel)
            cm1.Parameters.AddWithValue("Datum", startDatum)
            Dim ds1 As New HistoriekDataSet()
            Dim da1 As New OleDbDataAdapter(cm1)
            da1.Fill(ds1, "Historiek")

            Dim strSQL2 As String = "SELECT Leveringen.Datum, ""Levering"" AS Naam, LeveringDetails.Aantal AS Waarde " & _
                "FROM Leveringen INNER JOIN LeveringDetails ON Leveringen.Id = LeveringDetails.IdLevering " & _
                "WHERE LeveringDetails.IdArtikel = @ID AND Leveringen.Datum >= @Datum"
            Dim cm2 As New OleDbCommand(strSQL2, conn)
            cm2.Parameters.AddWithValue("ID", idArtikel)
            cm2.Parameters.AddWithValue("Datum", startDatum)
            Dim ds2 As New HistoriekDataSet()
            Dim da2 As New OleDbDataAdapter(cm2)
            da2.Fill(ds2, "Historiek")
            ds1.Merge(ds2)

            Dim strSQL3 As String = "SELECT Datum, ""Beweging"" AS Naam, - Aantal AS Waarde " & _
                "FROM Voorraadbewegingen " & _
                "WHERE IdArtikel = @ID AND Datum >= @Datum"
            Dim cm3 As New OleDbCommand(strSQL3, conn)
            cm3.Parameters.AddWithValue("ID", idArtikel)
            cm3.Parameters.AddWithValue("Datum", startDatum)
            Dim ds3 As New HistoriekDataSet()
            Dim da3 As New OleDbDataAdapter(cm3)
            da3.Fill(ds3, "Historiek")
            ds1.Merge(ds3)

            Return ds1
        Catch ex As Exception
            ' alleen loggen, exception inslikken
            log.WriteError(ex.ToString())
            Return Nothing
        Finally
            conn.Close()
        End Try
    End Function

#End Region

#Region "E-mailadressen"

    Public Shared Function EmailadresToevoegen(ByVal email As String) As Integer
        Dim conn As New OleDbConnection(My.Settings.fairshopConnectionString)
        Try
            conn.Open()
            Dim strSQL1 As String = "SELECT COUNT(*) FROM Emailadressen WHERE Email = ?"
            Dim cm1 As New OleDbCommand(strSQL1, conn)
            DalHelper.VoegParameterToe(cm1, email)
            Dim bestaatAl As Boolean = Convert.ToInt32(cm1.ExecuteScalar()) > 0
            If (Not bestaatAl) Then
                Dim strSQL2 As String = "INSERT INTO Emailadressen (Email) VALUES (?)"
                Dim cm2 As New OleDbCommand(strSQL2, conn)
                DalHelper.VoegParameterToe(cm2, email)
                Return cm2.ExecuteNonQuery()
            End If
            '' voegt alleen toe als het adres er nog niet in zit (in 1 query)
            'Dim strSQL As String = "INSERT INTO EmailAdressen " & _
            '                        "SELECT DISTINCT CStr(TempEmail) AS Email " & _
            '                        "FROM (SELECT ? AS TempEmail  " & _
            '                        "      FROM EmailAdressen  " & _
            '                        "      WHERE NOT EXISTS ( " & _
            '                        "           SELECT 1 FROM Emailadressen " & _
            '                        "           WHERE Email = ?) " & _
            '                        " )  AS EmailAlsHijNogNietBestaat"
            'Dim cm As New OleDbCommand(strSQL, conn)
            'DalHelper.VoegParameterToe(cm, email)
            'DalHelper.VoegParameterToe(cm, email)
            'Return cm.ExecuteNonQuery()
        Finally
            conn.Close()
        End Try
        Return 0
    End Function


#End Region

#Region "Helpers"

    Private Shared Sub GetNewIdentity(ByVal conn As OleDbConnection, _
            ByVal row As DataRow, Optional ByVal identityFieldName As String = "Id")
        Dim cm As New OleDbCommand(String.Format("SELECT @@IDENTITY FROM {0}", row.Table.TableName), conn)
        row(identityFieldName) = cm.ExecuteScalar()
        row.AcceptChanges()
    End Sub

#End Region

End Class
